/**
 * 
 */
package com.dalonedrow.module.chivalrysorcery.systems;

import com.dalonedrow.engine.sprite.base.SimpleVector2;
import com.dalonedrow.engine.systems.base.Interactive;
import com.dalonedrow.globalvariables.constants.hq.GlobalConstants;
import com.dalonedrow.module.chivalrysorcery.rpg.ChivSorcCharacter;
import com.dalonedrow.module.chivalrysorcery.rpg.ChivSorcInteractiveObject;
import com.dalonedrow.rpg.base.flyweights.EquipmentItemModifier;
import com.dalonedrow.rpg.base.flyweights.Scriptable;
import com.dalonedrow.rpg.base.systems.Equipment;

/**
 * @author Donald
 */
public final class ChivSorcEquipment
		implements
		Equipment<ChivSorcInteractiveObject, Scriptable<ChivSorcInteractiveObject>> {
	/** the one and only instance of the <code>HQEquipment</code> class. */
	private static ChivSorcEquipment	instance;
	/**
	 * Gives access to the singleton instance of {@link ChivSorcEquipment}.
	 * @return {@link ChivSorcEquipment}
	 */
	public static ChivSorcEquipment getInstance() {
		if (ChivSorcEquipment.instance == null) {
			ChivSorcEquipment.instance = new ChivSorcEquipment();
		}
		return ChivSorcEquipment.instance;
	}
	/** the list of equipment element modifiers. */
	private String[]	equipinfo;
	/** flag indicating the last ring that was equipped, right or left. */
	private boolean		ring	= false;
	/**
	 * Creates a new instance of {@link ChivSorcEquipment}.
	 */
	private ChivSorcEquipment() {
		equipinfo = new String[GlobalConstants.IO_EQUIPITEM_ELEMENT_NUMBER];
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean canEquipItem(final ChivSorcInteractiveObject target,
			final ChivSorcInteractiveObject toequip) throws Exception {
		// INCOMPLETE
		boolean val = false;
		if (toequip != null
				&& toequip.hasIOFlag(GlobalConstants.IO_02_ITEM)) {
			// IO IS AN ITEM
			if (target != null
					&& target.hasIOFlag(GlobalConstants.IO_01_PC)) {
				// ITEM EQUIPPED BY PC
				if (!toequip.getItemData().hasClassRestriction(
						GlobalConstants.CLASS_FLAGS[target.getPCData()
								.getProfession()
												])) {
					val = true;
				}
			} else if (target != null
					&& target.hasIOFlag(GlobalConstants.IO_03_NPC)) {
				// ITEM EQUIPPED BY NPC

			}
		}
		return val;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public float computeDamages(final ChivSorcInteractiveObject ioSource,
			final ChivSorcInteractiveObject ioTarget, final float ratioaim,
			final SimpleVector2 position) throws Exception {
		// set attacker as event sender, and send message to target
		HQScript.getInstance().setEventSender(ioSource);
		// tell target it is the victim of aggression
		HQScript.getInstance().sendIOScriptEvent(
				ioTarget, // target
				GlobalConstants.SM_57_AGGRESSION, // message
				null, // parameters,
				null// event name
				);
		float damages = 0f;
		if (ioSource != null
				&& ioTarget != null) {
			// *****************************
			// ** GET DAMAGE FROM THE ATTACK
			// *****************************
			String weaponMaterial = "BARE";
			String armorMaterial = "FLESH";
			float attack;
			if (ioSource.hasIOFlag(GlobalConstants.IO_01_PC)) { 
				// PLAYER ATTACK NPC
				ChivSorcCharacter player = ioSource.getPCData();
				int wpnId =
						player.getEquippedItem(GlobalConstants.EQUIP_SLOT_02_WEAPON);
				if (wpnId != -1
						&& Interactive.getInstance().hasIO(wpnId)) {
					ChivSorcInteractiveObject io =
							((DQInteractive) Interactive.getInstance())
									.getIO(wpnId);
					// GET THE MATERIAL OF THE WEAPON USED
					if (io != null
							&& io.getWeaponmaterial() != null) {
						weaponMaterial = io.getWeaponmaterial();
					}
					io = null;
				}
				attack = player.getFullAttack();
				// ROLL THE DICE
				for (int i = 0; i < attack; i++) {
					int roll = HQDice.getInstance().rollHQDice();
					if (roll == GlobalConstants.DICE_SKULL) {
						// ADD DAMAGE
						damages++;
					}
				}
				player = null;
			} else if (ioSource.hasIOFlag(GlobalConstants.IO_03_NPC)) {
				HQNPC.getInstance().computeNPCFullStats(ioSource);
				// NPC ATTACK
				if (ioSource.getWeaponmaterial() != null) {
					weaponMaterial = ioSource.getWeaponmaterial();
				}
				if (ioSource.getNPCData().getWeapon() != null) {
					ChivSorcInteractiveObject iow =
							ioSource.getNPCData().getWeapon();
					if (iow.getWeaponmaterial() != null) {
						weaponMaterial = iow.getWeaponmaterial();
					}
					iow = null;
				}
				attack = ioSource.getNPCData().getFullAttack();
				// apply spell buffs, debuffs, etc. to NPC attacker
				// no NPC spell buffs, debuffs used in HeroQuest
				// ROLL THE DICE
				for (int i = 0; i < attack; i++) {
					int roll = HQDice.getInstance().rollHQDice();
					if (roll == GlobalConstants.DICE_SKULL) {
						// ADD DAMAGE
						damages++;
					}
				}
			}
			// **********************************
			// ** GET HOW MUCH DAMAGE WAS BLOCKED
			// **********************************
			float absorb = 0f;
			if (damages > 0) {
				if (ioTarget.hasIOFlag(GlobalConstants.IO_01_PC)) {
					// TARGET WAS PC
					// check for how much damage can be absorbed
					float defend = ioTarget.getPCData().getFullDefend();
					// ROLL THE DICE
					for (int i = 0; i < defend; i++) {
						int roll = HQDice.getInstance().rollHQDice();
						if (roll == GlobalConstants.DICE_WHITE_SHIELD) {
							absorb++;
						}
					}
				} else {
					// TARGET WAS NPC
					HQNPC.getInstance().computeNPCFullStats(ioSource);
					float defend = ioTarget.getNPCData().getFullDefend();
					// ROLL THE DICE
					for (int i = 0; i < defend; i++) {
						int roll = HQDice.getInstance().rollHQDice();
						if (roll == GlobalConstants.DICE_BLACK_SHIELD) {
							absorb++;
						}
					}
				}
			}
			if (ioTarget.getArmormaterial() != null) {
				armorMaterial = ioTarget.getArmormaterial();
			}
			if (ioTarget.hasIOFlag(GlobalConstants.IO_01_PC)) {
				int rmrId = ioTarget.getPCData().getEquippedItem(
						GlobalConstants.EQUIP_SLOT_05_ARMOR);
				if (rmrId > -1
						&& Interactive.getInstance().hasIO(rmrId)) {
					ChivSorcInteractiveObject io =
							((DQInteractive) Interactive.getInstance())
									.getIO(rmrId);
					if (io != null && io.getArmormaterial() != null) {
						armorMaterial = io.getArmormaterial();
					}
				}
			}
			// ***************************
			// ** APPLY DAMAGES, EVEN IF 0
			// ***************************
			damages = Math.min(0, damages - absorb);
			if (ioTarget.hasIOFlag(GlobalConstants.IO_01_PC)) {
				// show a splat onscreen
				HQDamages.getInstance().addScreenSplat(null, damages);
				HQDamages.getInstance().damagePlayer(ioTarget.getRefId(),
						damages, 0, ioSource.getRefId(), null);
				HQDamages.getInstance().damagePlayerEquipment(
						ioTarget.getRefId(), damages);
			} else {
				HQDamages.getInstance().damageNPC(ioTarget.getRefId(),
						damages, ioSource.getRefId(), 0, null);
			}
		}
		return damages;
	}
	/** WORKING **/
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void equipItem(final ChivSorcInteractiveObject target,
			final ChivSorcInteractiveObject toequip) throws Exception {
		// *******
		// WORKING
		// *******
		if (target != null
				&& target.hasIOFlag(GlobalConstants.IO_01_PC)
				&& toequip != null
				&& toequip.hasIOFlag(GlobalConstants.IO_02_ITEM)
				&& !toequip.getItemData().hasClassRestriction(
						GlobalConstants.CLASS_FLAGS[target.getPCData()
								.getProfession()])
				&& ((DQInteractive) Interactive.getInstance()).getIO(
						toequip.getRefId()).equals(toequip)) {
			//HQInventory.getInstance().removeFromAllInventories(
			//		toequip, target);
			// no idea what this does
			toequip.setShow(GlobalConstants.SHOW_FLAG_ON_PLAYER); // on player

			// if target has a weapon equipped already, unequip it
			ChivSorcCharacter player = target.getPCData();
			if (toequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_01_DAGGER)
					|| toequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_02_1H)
					|| toequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_03_2H)
					|| toequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_04_BOW)) {
				// unequip old weapon
				int wpnId = player
						.getEquippedItem(GlobalConstants.EQUIP_SLOT_02_WEAPON);
				if (wpnId > -1
						&& Interactive.getInstance().hasIO(wpnId)) {
					unequip(target,
							((DQInteractive) Interactive.getInstance())
									.getIO(wpnId),
							false);
				}
				// equip new weapon
				player.setEquippedItem(GlobalConstants.EQUIP_SLOT_02_WEAPON, toequip);

				// if weapon is 2-handed, remove shield
				if (toequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_03_2H)
						|| toequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_04_BOW)) {
					int sldId = player.getEquippedItem(
							GlobalConstants.EQUIP_SLOT_03_SHIELD);
					if (sldId > -1
							&& Interactive.getInstance().hasIO(sldId)) {
						unequip(target,
								((DQInteractive) Interactive.getInstance())
										.getIO(sldId),
								false);
					}
				}
			} else if (toequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_05_SHIELD)) {
				// unequip old shield
				int sldId = player
						.getEquippedItem(GlobalConstants.EQUIP_SLOT_03_SHIELD);
				if (sldId > -1
						&& Interactive.getInstance().hasIO(sldId)) {
					unequip(target,
							((DQInteractive) Interactive.getInstance())
									.getIO(sldId),
							false);
				}
				// equip new shield
				player.setEquippedItem(GlobalConstants.EQUIP_SLOT_03_SHIELD, toequip);

				// if player has 2-handed weapon, unequip that
				int wpnId = player
						.getEquippedItem(GlobalConstants.EQUIP_SLOT_02_WEAPON);
				if (wpnId > -1
						&& Interactive.getInstance().hasIO(wpnId)) {
					ChivSorcInteractiveObject wpn =
							((DQInteractive) Interactive.getInstance()).getIO(
									wpnId);
					if (wpn.hasTypeFlag(GlobalConstants.OBJECT_TYPE_03_2H)
							|| wpn.hasTypeFlag(GlobalConstants.OBJECT_TYPE_04_BOW)) {
						unequip(target, wpn, false);
					}
				}
			} else if (toequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_10_RING)) {
				// check to see if ring already equipped
				int rltId = player.getEquippedItem(
						GlobalConstants.EQUIP_SLOT_00_RING_LEFT);
				ChivSorcInteractiveObject rlt = null;
				int rrtId = player.getEquippedItem(
						GlobalConstants.EQUIP_SLOT_01_RING_RIGHT);
				ChivSorcInteractiveObject rrt = null;
				if (rltId > -1
						&& Interactive.getInstance().hasIO(rltId)) {
					rlt = ((DQInteractive) Interactive.getInstance())
							.getIO(rltId);
				}
				if (rrtId > -1
						&& Interactive.getInstance().hasIO(rrtId)) {
					rrt = ((DQInteractive) Interactive.getInstance())
							.getIO(rrtId);
				}
				if (toequip.equals(rrt)
						|| toequip.equals(rlt)) {
					// DO NOT LET PLAYER EQUIP 2 OF THE SAME TYPE OF RING
					// send a message
				} else {
					int willequip = -1;
					if (rltId == -1) {
						willequip = GlobalConstants.EQUIP_SLOT_00_RING_LEFT;
					}
					if (rrtId == -1) {
						willequip = GlobalConstants.EQUIP_SLOT_01_RING_RIGHT;
					}
					if (willequip == -1) {
						// no empty ring slot. unequip one ring
						if (ring) {
							if (rrt != null) {
								unequip(target, rrt, false);
								willequip = GlobalConstants.EQUIP_SLOT_01_RING_RIGHT;
							} else {
								unequip(target, rlt, false);
								willequip = GlobalConstants.EQUIP_SLOT_00_RING_LEFT;
							}
							ring = !ring;
						}
					}
					// equip new ring
					player.setEquippedItem(willequip, toequip);
				}
			} else if (toequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_08_ARMOR)) {
				// unequip old armor
				int rmrId = player
						.getEquippedItem(GlobalConstants.EQUIP_SLOT_05_ARMOR);
				if (rmrId > -1
						&& Interactive.getInstance().hasIO(rmrId)) {
					unequip(target,
							((DQInteractive) Interactive.getInstance())
									.getIO(rmrId),
							false);
				}
				// equip new armor
				player.setEquippedItem(GlobalConstants.EQUIP_SLOT_05_ARMOR, toequip);
			} else if (toequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_11_BRACERS)) {
				// unequip old bracers
				int bracerId = player.getEquippedItem(
						GlobalConstants.EQUIP_SLOT_07_BRACERS);
				if (bracerId > -1
						&& Interactive.getInstance().hasIO(bracerId)) {
					unequip(target,
							((DQInteractive) Interactive.getInstance())
									.getIO(bracerId),
							false);
				}
				// equip new bracers
				player.setEquippedItem(
						GlobalConstants.EQUIP_SLOT_07_BRACERS, toequip);
			} else if (toequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_12_BOOTS)) {
				// unequip old boots
				int bootId = player.getEquippedItem(
						GlobalConstants.EQUIP_SLOT_08_BOOTS);
				if (bootId > -1
						&& Interactive.getInstance().hasIO(bootId)) {
					unequip(target,
							((DQInteractive) Interactive.getInstance())
									.getIO(bootId),
							false);
				}
				// equip new boots
				player.setEquippedItem(GlobalConstants.EQUIP_SLOT_08_BOOTS, toequip);
			} else if (toequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_09_HELMET)) {
				// unequip old helmet
				int hlmId = player
						.getEquippedItem(GlobalConstants.EQUIP_SLOT_06_HELMET);
				if (hlmId > -1
						&& Interactive.getInstance().hasIO(hlmId)) {
					unequip(target,
							((DQInteractive) Interactive.getInstance())
									.getIO(hlmId),
							false);
				}
				// equip new helmet
				player.setEquippedItem(GlobalConstants.EQUIP_SLOT_06_HELMET, toequip);
			}
			recreatePlayerAppearance(target);
			ChivSorcPlayer.getInstance().computePlayerFullStats(target);
		}
	}
	/** WORKING **/
	/**
	 * {@inheritDoc}
	 */
	@Override
	public float getEquipmentModifier(final ChivSorcInteractiveObject io,
			final int ident, final float trueVal) throws Exception {
		float toadd = 0f;
		if (io != null
				&& io.hasIOFlag(GlobalConstants.IO_01_PC)) {
			ChivSorcCharacter player = io.getPCData();
			for (int i = 0; i < GlobalConstants.MAX_EQUIPED; i++) {
				int eqpId = player.getEquippedItem(i);
				if (eqpId > -1
						&& Interactive.getInstance().hasIO(eqpId)) {
					ChivSorcInteractiveObject toequip =
							((DQInteractive) Interactive.getInstance())
									.getIO(eqpId);
					if (toequip != null
							&& toequip.hasIOFlag(GlobalConstants.IO_02_ITEM)
							&& toequip.getItemData().getEquipitem() != null) {
						HQIOEquipItem equipItem =
								toequip.getItemData()
										.getEquipitem();
						EquipmentItemModifier elem =
								equipItem.getElement(ident);
						if (elem.hasFlag(1)) {
							// modifier is percentage, so if modifier is 5% and
							// true value is 18, modifier equals 18 * 5 * .01
							// which is 0.9
							toadd +=
									trueVal * elem.getValue()
											* GlobalConstants.DIV_100;
						} else {
							// modifier is a whole, so if modifier is +2,
							// 2 is returned
							toadd += elem.getValue();
						}
					}
				}
			}
		}
		return toadd;
	}
	/** WORKING **/
	/**
	 * {@inheritDoc}
	 */
	@Override
	public ChivSorcInteractiveObject getFreshItem(
			final Scriptable<ChivSorcInteractiveObject> script) throws Exception {
		ChivSorcInteractiveObject io =
				(ChivSorcInteractiveObject) Interactive.getInstance().getNewIO();
		io.setItemData(new HQItemData());
		io.getItemData().setEquipitem(new HQIOEquipItem());
		io.setScript(script);
		script.setIO(io);
		HQScript.getInstance().sendInitScriptEvent(io);
		return io;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public float getHitValue(final char[] text) {
		final int three = 3, four = 4, five = 5;
		float val = -1;
		if (text.length >= five) {
			if ((text[0] == 'H' || text[0] == 'h')
					&& (text[1] == 'I' || text[1] == 'i')
					&& (text[2] == 'T' || text[1] == 't')
					&& text[three] == '_') {
				val = text[four];
			}
		}
		return val;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public float getHitValue(final String text) {
		return this.getHitValue(text.toCharArray());
	}
	/** WORKING **/
	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getObjectTypeFlag(final char c) throws Exception {
		int val = 0;
		switch (Character.toLowerCase(c)) {
		case 'w':
			val = GlobalConstants.OBJECT_TYPE_00_WEAPON;
			break;
		case 'd':
			val = GlobalConstants.OBJECT_TYPE_01_DAGGER;
			break;
		case '1':
			val = GlobalConstants.OBJECT_TYPE_02_1H;
			break;
		case '2':
			val = GlobalConstants.OBJECT_TYPE_03_2H;
			break;
		case 'b':
			val = GlobalConstants.OBJECT_TYPE_04_BOW;
			break;
		case 's':
			val = GlobalConstants.OBJECT_TYPE_05_SHIELD;
			break;
		case 'f':
			val = GlobalConstants.OBJECT_TYPE_06_FOOD;
			break;
		case 'g':
			val = GlobalConstants.OBJECT_TYPE_07_GOLD;
			break;
		case 'r':
			val = GlobalConstants.OBJECT_TYPE_10_RING;
			break;
		case 'a':
			val = GlobalConstants.OBJECT_TYPE_08_ARMOR;
			break;
		case 'h':
			val = GlobalConstants.OBJECT_TYPE_09_HELMET;
			break;
		case 'c':
			val = GlobalConstants.OBJECT_TYPE_11_BRACERS;
			break;
		case 'o':
			val = GlobalConstants.OBJECT_TYPE_12_BOOTS;
			break;
		default:
			throw new Exception("Invalid Equipment prefix: " + c);
		}
		return val;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getPlayerWeaponType(final ChivSorcInteractiveObject pc)
			throws Exception {
		int type = GlobalConstants.WEAPON_BARE;
		if (pc != null) {
			ChivSorcCharacter player = pc.getPCData();
			int wpnId =
					player.getEquippedItem(GlobalConstants.EQUIP_SLOT_02_WEAPON);
			if (wpnId != -1
					&& Interactive.getInstance().hasIO(wpnId)) {
				ChivSorcInteractiveObject toequip =
						((DQInteractive) Interactive.getInstance())
								.getIO(wpnId);
				if (toequip != null) {
					if (toequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_01_DAGGER)) {
						type = GlobalConstants.WEAPON_DAGGER;
					}
					if (toequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_02_1H)) {
						type = GlobalConstants.WEAPON_1H;
					}
					if (toequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_03_2H)) {
						type = GlobalConstants.WEAPON_2H;
					}
					if (toequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_04_BOW)) {
						type = GlobalConstants.WEAPON_BOW;
					}
				}
			}
		}
		return type;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public float getSpecialValue(final ChivSorcInteractiveObject item,
			final long val) {
		// NOT USED
		return 0;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void identifyAll(final ChivSorcInteractiveObject pc) {
		// NOT USED
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void init() {
		equipinfo[GlobalConstants.IO_EQUIPITEM_ELEMENT_ATTACK] = "attack";
		equipinfo[GlobalConstants.IO_EQUIPITEM_ELEMENT_BODY] = "body";
		equipinfo[GlobalConstants.IO_EQUIPITEM_ELEMENT_DEFEND] = "defend";
		equipinfo[GlobalConstants.IO_EQUIPITEM_ELEMENT_MIND] = "mind";
		equipinfo[GlobalConstants.IO_EQUIPITEM_ELEMENT_MOVEMENT] = "movement";
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean isPlayerEquippedWithItem(final ChivSorcInteractiveObject pc,
			final ChivSorcInteractiveObject item) throws Exception {
		boolean val = false;
		if (pc != null) {
			for (int i = 0; i < GlobalConstants.MAX_EQUIPED; i++) {
				ChivSorcCharacter player = pc.getPCData();
				// get the ref id for the
				int equipId = player.getEquippedItem(i);
				if (equipId != -1
						&& Interactive.getInstance().hasIO(equipId)) {
					ChivSorcInteractiveObject toequip =
							((DQInteractive) Interactive.getInstance())
									.getIO(equipId);
					if (toequip.equals(item)) {
						val = true;
						break;
					}
				}
			}
		}
		return val;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void launchPlayerReadyWeapon(final ChivSorcInteractiveObject pc) {
		// PLAY ANIMATION WHEN PLAYER UNSHEATHES WEAPON.
		// NOT NEEDED
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void launchPlayerUnReadyWeapon(final ChivSorcInteractiveObject pc) {
		// do nothing. this method should ready animations and appearance
		// for the player sheathing his weapon.
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void recreatePlayerAppearance(final ChivSorcInteractiveObject pc) {
		// TODO Auto-generated method stub
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void release(final ChivSorcInteractiveObject player, final long id)
			throws Exception {
		if (!player.hasIOFlag(GlobalConstants.IO_01_PC)) {
			throw new Exception(
					"Can only release items equipped on RPGCharacter objects");
		}
		if (id != 0) {
			for (int i = 0; i < GlobalConstants.MAX_EQUIPED; i++) {
				if (player.getPCData().getEquippedItem(i) == id) {
					player.getPCData().setEquippedItem(i, 0);
				}
			}
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void release(final long id, final ChivSorcInteractiveObject pc)
			throws Exception {
		release(pc, id);
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void releaseAll(final ChivSorcInteractiveObject io) {
		if (io != null) {
			releaseEquipItem(io);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void releaseEquipItem(final ChivSorcInteractiveObject io) {
		if (io != null
				&& io.hasIOFlag(GlobalConstants.IO_02_ITEM)
				&& io.getItemData() != null
				&& io.getItemData().getEquipitem() != null) {
			io.getItemData().getEquipitem().free();
			io.getItemData().setEquipitem(null);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void removeAllSpecial(final ChivSorcInteractiveObject io) {
		// NOT USED
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void removeClassRestriction(final ChivSorcInteractiveObject item,
			final int restriction) {
		if (item != null
				&& item.hasIOFlag(GlobalConstants.IO_02_ITEM)) {
			item.getItemData().removeClassRestriction(restriction);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void removeRaceRestriction(final ChivSorcInteractiveObject item,
			final int restriction) {
		if (item != null
				&& item.hasIOFlag(GlobalConstants.IO_02_ITEM)) {
			item.getItemData().removeRaceRestriction(restriction);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setClassRestriction(final ChivSorcInteractiveObject item,
			final int restriction) {
		if (item != null
				&& item.hasIOFlag(GlobalConstants.IO_02_ITEM)) {
			item.getItemData().addClassRestriction(restriction);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setEquip(final ChivSorcInteractiveObject io, final String param1,
			final String param2, final float val, final int flag) {
		if (io != null
				&& io.hasIOFlag(GlobalConstants.IO_02_ITEM)) {

			if (io.getItemData().getEquipitem() == null) {
				io.getItemData().setEquipitem(new HQIOEquipItem());
			}

			if (!param1.equalsIgnoreCase("-s")) {
				/*
				 * HANDLE SPECIAL VALUES for (int i =
				 * IO_EQUIPITEM_ELEMENT_SPECIAL_1; i <=
				 * IO_EQUIPITEM_ELEMENT_SPECIAL_4; i++) { if
				 * (io->_itemdata->equipitem->elements[i].special ==
				 * IO_SPECIAL_ELEM_NONE) { if (!stricmp(param2, "PARALYSE"))
				 * io->_itemdata->equipitem->elements[i].special =
				 * IO_SPECIAL_ELEM_PARALYZE; else if (!stricmp(param2,
				 * "DRAINLIFE")) io->_itemdata->equipitem->elements[i].special =
				 * IO_SPECIAL_ELEM_DRAIN_LIFE;
				 * io->_itemdata->equipitem->elements[i].value = val;
				 * io->_itemdata->equipitem->elements[i].flags = flags; return;
				 * } }
				 */
			} else {
				// setting a special value.
				// clear all non-special values
				for (int i = 0; i < GlobalConstants.IO_EQUIPITEM_ELEMENT_NUMBER; i++) {
					if (param2.equalsIgnoreCase(equipinfo[i])) {
						io.getItemData().getEquipitem().getElement(i)
								.setValue(val);
						io.getItemData().getEquipitem().getElement(i)
								.setSpecial(0);
						io.getItemData().getEquipitem().getElement(i)
								.setFlag(flag);
						return;
					}
				}
			}
		}
	}
	/** WORKING **/
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setEquipmentModifier(final ChivSorcInteractiveObject io,
			final int element, final float val, final int flag) {
		if (io != null
				&& io.hasIOFlag(GlobalConstants.IO_02_ITEM)) {
			io.getItemData().getEquipitem().getElement(element)
					.setValue(val);
			io.getItemData().getEquipitem().getElement(element)
					.setSpecial(0);
			io.getItemData().getEquipitem().getElement(element)
					.setFlag(flag);
		}
	}
	/** WORKING **/
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setObjectType(final ChivSorcInteractiveObject item, final char c,
			final boolean isSet) throws Exception {
		// avoid erroneous objects
		if (item != null) {
			// retrieves flag
			int flagg = getObjectTypeFlag(c);
			if (isSet) { // add flag
				item.addTypeFlag(flagg);
			} else { // remove flag
				item.removeTypeFlag(flagg);
			}
		}
	}
	/** WORKING **/
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setObjectType(final ChivSorcInteractiveObject item, final int type,
			final boolean isSet)
			throws Exception {
		// avoid erroneous objects
		if (item != null) {
			if (isSet) { // add flag
				item.addTypeFlag(type);
			} else { // remove flag
				item.removeTypeFlag(type);
			}
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setRaceRestriction(final ChivSorcInteractiveObject item,
			final int restriction) {
		if (item != null
				&& item.hasIOFlag(GlobalConstants.IO_02_ITEM)) {
			item.getItemData().addRaceRestriction(restriction);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean strikeCheck(final ChivSorcInteractiveObject ioSource,
			final ChivSorcInteractiveObject ioWeapon, final float ratioaim,
			final boolean showBlood, final int targ) throws Exception {
		boolean ret = false;
		int source = ioSource.getRefId();
		int weapon = ioWeapon.getRefId();
		// check for weapon effects
		/*
		 * float drain_life = ARX_EQUIPMENT_GetSpecialValue(io_weapon,
		 * IO_SPECIAL_ELEM_DRAIN_LIFE); float paralyse =
		 * ARX_EQUIPMENT_GetSpecialValue(io_weapon, IO_SPECIAL_ELEM_PARALYZE);
		 */
		// try to hit the target
		ChivSorcInteractiveObject ioTarget =
				((DQInteractive) Interactive.getInstance()).getIO(targ);
		float damages = computeDamages(ioSource, ioTarget, ratioaim, null);
		if (ioTarget.hasIOFlag(GlobalConstants.IO_03_NPC)) {
			ret = true;
			ioTarget.setSparkNBlood(0);
			ioTarget.getNPCData().setSplatTotNb(0);
			/*
			 * APPLY EFFECT WHEN HIT - DRAIN LIFE, PARALYSIS, ETC... if
			 * (drain_life > 0.f) { float life_gain = __min(dmgs, drain_life);
			 * life_gain = __min(life_gain, target->_npcdata->life); life_gain =
			 * __max(life_gain, 0.f); ARX_DAMAGES_HealInter(io_source,
			 * life_gain); } if (paralyse > 0.f) { float ptime = __min(dmgs *
			 * 1000.f, paralyse); ARX_SPELLS_Launch(SPELL_PARALYSE, weapon,
			 * SPELLCAST_FLAG_NOMANA | SPELLCAST_FLAG_NOCHECKCANCAST , 5,
			 * EVERYTHING_IN_SPHERE[jj], (long)(ptime)); }
			 */
		}
		if (ioSource.hasIOFlag(GlobalConstants.IO_01_PC)) {
			// if source was player, check for weapon wearing down
			// ARX_DAMAGES_DurabilityCheck(ioWeapon, 0.2f);
		}
		if (damages > 0) {
			// apply sparks to target sprite on screen.
			// dont do now, maybe later
		}
		return ret;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void unequip(final ChivSorcInteractiveObject target,
			final ChivSorcInteractiveObject tounequip, final boolean isDestroyed)
			throws Exception {
		if (target != null
				&& tounequip != null
				&& target.hasIOFlag(GlobalConstants.IO_01_PC)) {
			for (int i = 0; i < GlobalConstants.MAX_EQUIPED; i++) {
				ChivSorcCharacter player = target.getPCData();
				if (player.getEquippedItem(i) != 0
						&& Interactive.getInstance().hasIO(
								player.getEquippedItem(i))
						&& Interactive.getInstance()
								.getIO(player.getEquippedItem(i))
								.equals(tounequip)) {
					// below line unlinks 3D objects in Arx Fatalis
					// EERIE_LINKEDOBJ_UnLinkObjectFromObject(target->obj,
					// tounequip->obj);
					// release the item from the player
					release(player.getEquippedItem(i), target);
					/*
					 * more 3D code target->bbox1.x = 9999; target->bbox2.x =
					 * -9999;
					 */

					if (!isDestroyed) {
						/*
						 * if (HQInventory.getInstance().canBePutInInventory(
						 * tounequip, target)) { // TO DO - PUT IN PLAYER
						 * INVENTORY } else { // drop the item on the ground
						 * //HQInventory.getInstance().putInFrontOfPlayer( //
						 * tounequip, target, false); }
						 */
					} else {
						// destory the item
					}
					// TO DO - SEND SCRIPT EVENT THAT PLAYER UNEQUIPPED THIS
					// ITEM
					HQScript.getInstance().setEventSender(tounequip);
					HQScript.getInstance().sendIOScriptEvent(
							target,
							GlobalConstants.SM_007_EQUIPOUT,
							null,
							null
							);
					HQScript.getInstance().setEventSender(target);
					HQScript.getInstance().sendIOScriptEvent(
							tounequip,
							GlobalConstants.SM_007_EQUIPOUT,
							null,
							null
							);
				}
			}
			if (tounequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_09_HELMET)
					|| tounequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_08_ARMOR)
					|| tounequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_11_BRACERS)
					|| tounequip.hasTypeFlag(GlobalConstants.OBJECT_TYPE_12_BOOTS)) {
				recreatePlayerAppearance(target);
			}
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void unequipAllOnPlayer(final ChivSorcInteractiveObject pc)
			throws Exception {
		for (int i = 0; i < GlobalConstants.MAX_EQUIPED; i++) {
			ChivSorcCharacter player = pc.getPCData();
			// get the ref id for the
			int equipId = player.getEquippedItem(i);
			if (equipId != -1
					&& Interactive.getInstance().hasIO(equipId)) {
				unequip(pc,
						((DQInteractive) Interactive.getInstance())
								.getIO(equipId), false);
			}
		}
		ChivSorcPlayer.getInstance().computePlayerFullStats(pc);
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void unequipPlayerWeapon(final ChivSorcInteractiveObject pc)
			throws Exception {
		ChivSorcCharacter player = pc.getPCData();
		int wpnId = player.getEquippedItem(GlobalConstants.EQUIP_SLOT_02_WEAPON);
		if (wpnId > -1
				&& Interactive.getInstance().hasIO(wpnId)) {
			ChivSorcInteractiveObject tounequip =
					((DQInteractive) Interactive.getInstance()).getIO(wpnId);
			unequip(pc, tounequip, false);
		}
		player.setEquippedItem(GlobalConstants.EQUIP_SLOT_02_WEAPON, -1);
	}
}
